from fastapi import APIRouter
from pyzbar import pyzbar
from PIL import Image, ImageEnhance, ImageFilter
import os
import sys
import requests
from io import BytesIO
from pyzbar import pyzbar
from PIL import Image
import pdf2image
import warnings
import contextlib
from fastapi import HTTPException
from pydantic import BaseModel, Field
from datetime import datetime

def yyyymmdd_to_milliseconds(date_str):
    """
    将六位时间(YYYYMMDD)转换为毫秒时间戳
    
    参数:
        date_str: 六位日期字符串，如 "20250502"
        
    返回:
        对应日期的毫秒时间戳(UTC)
    调用：
    test_yyyymmdd_to_milliseconds()
    """
    try:
        # 解析日期字符串
        dt = datetime.strptime(date_str, "%Y%m%d")
        # 转换为毫秒时间戳
        timestamp_ms = int(dt.timestamp() * 1000)
        return timestamp_ms
    except ValueError as e:
        raise ValueError(f"无效的日期格式: {date_str}，请使用YYYYMMDD格式") from e

def test_yyyymmdd_to_milliseconds():
      # 使用示例
    date_str = "20250502"  # 2025年5月2日
    milliseconds = yyyymmdd_to_milliseconds(date_str)
    print(f"日期 {date_str} 对应的毫秒时间戳: {milliseconds}")
    
    # 验证转换是否正确
    from datetime import datetime
    dt = datetime.fromtimestamp(milliseconds/1000)
    print(f"转换回日期: {dt.strftime('%Y-%m-%d')}")  

def milliseconds_to_yyyymmdd(timestamp_ms, timezone=None):
    """
    将毫秒时间戳转换为六位时间(YYYYMMDD)
    
    参数:
        timestamp_ms: 毫秒时间戳
        timezone: 可选时区字符串(如'Asia/Shanghai')，默认UTC
        
    返回:
        六位日期字符串，如 "20250502"
    """
    try:
        # 转换为秒并创建datetime对象
        timestamp_sec = timestamp_ms / 1000
        if timezone:
            from pytz import timezone as tz
            dt = datetime.fromtimestamp(timestamp_sec, tz(timezone))
        else:
            dt = datetime.utcfromtimestamp(timestamp_sec)
        
        # 格式化为YYYYMMDD
        return dt.strftime("%Y%m%d")
    except ValueError as e:
        raise ValueError(f"无效的时间戳: {timestamp_ms}") from e
    except ImportError:
        raise ImportError("使用时区需要安装pytz: pip install pytz")

def test_milliseconds_to_yyyymmdd():
        # 测试数据: 2025年5月2日的毫秒时间戳
    timestamp_ms = 1746144000000
    # 转换为六位时间(UTC)
    date_str = milliseconds_to_yyyymmdd(timestamp_ms)
    print(f"毫秒时间戳 {timestamp_ms} 对应的六位时间(UTC): {date_str}")
    
# 定义请求和响应模型
class PDFUrlRequest(BaseModel):
    pdf_url: str = Field(..., description="PDF文件的URL地址")

class InvoiceResponse(BaseModel):
    invoice_number: str = Field(None, description="发票号码")
    amount: str = Field(None, description="金额")
    date: str = Field(None, description="开票日期")
    success: bool = Field(..., description="是否成功识别")
    message: str = Field("", description="错误信息")

image_qr_router = APIRouter(
    prefix="/image_qr",
    tags=["image_qr"],
    responses={404: {"description": "Not found"}},
)

# 1. 全局忽略Python警告
warnings.filterwarnings("ignore")

# 2. 临时关闭stderr（彻底屏蔽C级别的zbar警告）
@contextlib.contextmanager
def suppress_stderr():
    """临时重定向stderr到/dev/null"""
    fd = sys.stderr.fileno()
    def _redirect_stderr(to):
        sys.stderr.close()  # 关闭当前stderr
        os.dup2(to.fileno(), fd)  # 将stderr重定向到目标
        sys.stderr = os.fdopen(fd, 'w')  # 重新打开
    
    with os.fdopen(os.dup(fd), 'w') as old_stderr:  # 备份原stderr
        with open(os.devnull, 'w') as file:
            _redirect_stderr(to=file)  # 重定向到/dev/null
        try:
            yield
        finally:
            _redirect_stderr(to=old_stderr)  # 恢复原stderr

@image_qr_router.post("/read_pdf_url_qr_code_api", response_model=InvoiceResponse)
async def read_pdf_url_qr_code_api(request: PDFUrlRequest):
    """
    API端点：识别PDF URL中的二维码并返回发票信息
    
    参数:
        - pdf_url: PDF文件的URL地址
    
    返回:
        - 包含发票号码、金额、日期的JSON响应
        - 如果识别失败，返回错误信息
    """
    try:
        # 调用现有的识别函数
        result = read_pdf_url_qr_code(request.pdf_url)
        
        if result:
            invoice_number, amount, date = result
            return InvoiceResponse(
                invoice_number=invoice_number,
                amount=amount,
                date=date,
                success=True,
                message="识别成功"
            )
        else:
            return InvoiceResponse(
                success=False,
                message="无法识别PDF中的二维码"
            )
    
    except Exception as e:
        # 捕获所有异常并返回友好的错误信息
        return InvoiceResponse(
            success=False,
            message=f"处理过程中发生错误: {str(e)}"
        )

def read_pdf_url_qr_code(pdf_url: str):
    """
    功能：识别pdf_url中首张图片中的二维码；
    返回：发票号码，金额，开票日期（如0250414,返回毫米时间戳）
    调用：
        # 测试PDF URL
    pdf_url = "限公司_20250331144352.pdf"
    result = read_pdf_url_qr_code(pdf_url)
    
    if result:
        invoice_num, amount, date = result
        print(f"发票号: {invoice_num}")
        print(f"金额: {amount}")
        print(f"日期: {date}")
    else:
        print("PDF识别失败")
        """
    try:
        # 下载PDF（增加超时和重试）
        with requests.get(pdf_url, timeout=10) as response:
            response.raise_for_status()
            
            # 在静默环境中处理二维码识别
            with suppress_stderr():
                images = pdf2image.convert_from_bytes(
                    response.content,
                    first_page=1,
                    last_page=1,
                    dpi=200,
                    thread_count=1,
                    poppler_path=None
                )
                if not images:
                    return None
                
                # 强制转换为RGB模式
                img = images[0].convert('RGB')
                decoded_objects = pyzbar.decode(img)
                if not decoded_objects:
                    return None
                
                # 解析数据
                qr_data = decoded_objects[0].data.decode('utf-8')
                fields = qr_data.split(',')
                
                date_str = fields[5]
                date_ms = yyyymmdd_to_milliseconds(date_str)
                return fields[3], fields[4], date_ms  # 发票号,金额,日期
    
    except Exception:
        return None
    
def read_qr_code_2(image_path):
    """
    功能：发票图片中二维码内容识别(根据文件路径)；
    返回：发票号码，金额，开票日期（如0250414）
    调用：
    invoice_number, amount, date=read_qr_code_2('input_files\二维码识别失败-发票.png')
    if invoice_number is None:
        print("未能成功识别二维码数据")
    else:
        print(invoice_number, amount, date)
        """
    # 打开图像文件
    img = Image.open(image_path)
    
    # 图像预处理
    # 转换为灰度图
    img = img.convert('L')
    
    # 增强对比度
    enhancer = ImageEnhance.Contrast(img)
    img = enhancer.enhance(2.0)  # 增强对比度2倍
    
    # 锐化图像
    img = img.filter(ImageFilter.SHARPEN)
    
    # 二值化处理
    threshold = 150  # 阈值可根据实际情况调整
    img = img.point(lambda p: p > threshold and 255)
    
    # 解码二维码
    decoded_objects = pyzbar.decode(img)
    
    if not decoded_objects:
        print("未能识别二维码，尝试其他方法...")
        # 尝试调整阈值再次识别
        for th in [100, 120, 180, 200]:
            temp_img = img.point(lambda p: p > th and 255)
            decoded_objects = pyzbar.decode(temp_img)
            if decoded_objects:
                break

    # # 打印结果
    # for obj in decoded_objects:
    #     print("类型:", obj.type)
    #     print("数据:", obj.data.decode('utf-8'))
    #     print("位置:", obj.rect)
    
    if not decoded_objects:
        print("警告: 未能识别任何二维码")
        return None  # 如果没有识别到二维码，直接返回None
    
    # 只有在成功识别二维码后才执行下面的代码
    qr_data = decoded_objects[0].data.decode('utf-8')
    fields = qr_data.split(',')
    
    # 4. 检查字段数量是否足够（至少7个字段，索引3=发票号，4=金额，5=日期）
    if len(fields) < 6:
        return None  # 或 raise Exception("二维码数据格式不符")
    
    # 5. 提取关键字段
    invoice_number = fields[3]  # 发票号（第4个字段）
    amount = fields[4]         # 金额（第5个字段）
    date = fields[5]           # 日期（第6个字段）
    
    return invoice_number, amount, date  # 直接返回三个值  
    
    
